Load Packages

library(tidyverse)
Warning: package ‘tidyverse’ was built under R version 4.1.3
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ---------------------------------------------------------------------------------------- tidyverse 1.3.1 --
√ ggplot2 3.3.5     √ purrr   0.3.4
√ tibble  3.1.6     √ dplyr   1.0.8
√ tidyr   1.2.0     √ stringr 1.4.0
√ readr   2.1.2     √ forcats 0.5.1
Warning: package ‘ggplot2’ was built under R version 4.1.3
Warning: package ‘tibble’ was built under R version 4.1.3
Warning: package ‘tidyr’ was built under R version 4.1.3
Warning: package ‘readr’ was built under R version 4.1.3
Warning: package ‘purrr’ was built under R version 4.1.3
Warning: package ‘dplyr’ was built under R version 4.1.3
Warning: package ‘stringr’ was built under R version 4.1.3
Warning: package ‘forcats’ was built under R version 4.1.3
-- Conflicts ------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(ggthemes)
Warning: package ‘ggthemes’ was built under R version 4.1.3
library(scales)
Warning: package ‘scales’ was built under R version 4.1.3

Attaching package: ‘scales’

The following object is masked from ‘package:purrr’:

    discard

The following object is masked from ‘package:readr’:

    col_factor
library(readxl)
Warning: package ‘readxl’ was built under R version 4.1.3
library(plotly)
Warning: package ‘plotly’ was built under R version 4.1.3
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout

Making Dataframes

color_a <- c("#58b5e1","#1c5b5a","#46ebdc","#1f4196","#e28de2","#818bd7","#e4ccf1","#82185f","#f849b6","#000000","#5e34bc","#b7d165","#30d52e","#ff5357")
color_na <- c("#1c5b5a","#46ebdc","#e28de2","#818bd7","#e4ccf1","#82185f","#f849b6","#000000","#5e34bc","#30d52e","#ff5357")
counties <- c('Anson', 'Cabarrus', 'Catawba', 'Chester', 'Cleveland', 'Gaston', 'Iredell', 'Lancaster', 'Lincoln', 'Mecklenburg', 'Rowan', 'Stanly', 'Union', 'York')
attainment_lvl <- c('Highest Degree: Less than a High School Diploma', 'Highest Degree: High School Diploma', 'Highest Degree: Some College, No Degree', "Highest Degree: Associate's Degree", "Highest Degree: Bachelor's Degree", "Highest Degree: Graduate or Professional Degree")
foreign_detail <- c('Foreign-Born: Africa', 'Foreign-Born: Asia', 'Foreign-Born: Europe', 'Foreign-Born: Latin America', 'Place of Birth Total')

countypop <- rbind(read_csv("cc-est2019-agesex-37.csv", show_col_types = F),
                   read_csv("cc-est2019-agesex-45.csv", show_col_types = F)) %>%
  select(-SUMLEV, -STATE, -COUNTY) %>%
  mutate(CTYNAME = gsub(' County', '', CTYNAME),
         YEAR = as.integer(YEAR + 2007)) %>%
  filter(CTYNAME %in% counties, YEAR >= 2010,
         !(STNAME == 'South Carolina' & CTYNAME == 'Union')) %>%
  distinct()
# Year 3 is 2010, Year 12 is 2019

# Making Charlotte Region
cr <- countypop[1:10,] %>%
  mutate(CTYNAME = 'Charlotte Region')
for(i in 4:length(colnames(countypop))) {
  for(j in 1:10){
    cr[j,i] <- sum((countypop %>% filter(YEAR == j+2009))[i])
  }
}

# Making Age & Gender data frame
pop_age_gender <- rbind(countypop, cr)
countypop <- cr %>% transmute(YEAR = YEAR, CHARLOTTEPOP = POPESTIMATE) %>% right_join(countypop, by = 'YEAR') %>% mutate(PROPORTION = POPESTIMATE / CHARLOTTEPOP) %>%
  group_by(CTYNAME) %>%
  mutate(CHANGE = ifelse(YEAR == 2010, 0, POPESTIMATE/lag(POPESTIMATE, default = first(YEAR)) - 1)) %>%
  ungroup()

pop_age_gender <- pop_age_gender %>%
  select(-contains('_TOT'), -POPEST_FEM, -POPEST_MALE, -AGE16PLUS_MALE, -AGE16PLUS_FEM, -AGE18PLUS_FEM, -AGE18PLUS_MALE, -UNDER5_FEM, -UNDER5_MALE, -AGE1544_FEM, -AGE1544_MALE, -MEDIAN_AGE_FEM, -MEDIAN_AGE_MALE, -AGE65PLUS_FEM,-AGE65PLUS_MALE, -AGE513_FEM, -AGE513_MALE, -AGE4564_FEM, -AGE4564_MALE, -AGE2544_FEM, -AGE2544_MALE, -AGE1824_FEM, -AGE1824_MALE, -AGE1417_FEM, -AGE1417_MALE) %>%
  rename(AGE004_FEM = AGE04_FEM, AGE004_MALE = AGE04_MALE, AGE0509_MALE = AGE59_MALE, AGE0509_FEM = AGE59_FEM)
pop_age_gender <- pop_age_gender %>%
  pivot_longer(cols = colnames(pop_age_gender[,5:40]), names_to = 'DEMO', values_to = 'POP') %>%
  mutate(PERCENTAGE = POP/POPESTIMATE)
pop_age_gender <- pop_age_gender %>%
  mutate(GENDER = as.factor(ifelse(grepl('MALE', pop_age_gender$DEMO),'MALE','FEMALE')),
         DEMO = gsub('_FEM','', DEMO),
         DEMO = gsub('_MALE','', DEMO),
         DEMO = case_when(DEMO == 'AGE004' ~ '0-04',
                          DEMO == 'AGE0509' ~ '05-09',
                          DEMO == 'AGE1014' ~ '10-14',
                          DEMO == 'AGE1519' ~ '15-19',
                          DEMO == 'AGE2024' ~ '20-24',
                          DEMO == 'AGE2529' ~ '25-29',
                          DEMO == 'AGE3034' ~ '30-34',
                          DEMO == 'AGE3539' ~ '35-39',
                          DEMO == 'AGE4044' ~ '40-44',
                          DEMO == 'AGE4549' ~ '45-49',
                          DEMO == 'AGE5054' ~ '50-54',
                          DEMO == 'AGE5559' ~ '55-59',
                          DEMO == 'AGE6064' ~ '60-64',
                          DEMO == 'AGE6569' ~ '65-69',
                          DEMO == 'AGE7074' ~ '70-74',
                          DEMO == 'AGE7579' ~ '75-79',
                          DEMO == 'AGE8084' ~ '80-84',
                          DEMO == 'AGE85PLUS' ~ '85 and Over'))

# Making ethnicity data frame
ethpop <- rbind(read_csv("cc-est2019-alldata-37.csv", show_col_types = F),
                   read_csv("cc-est2019-alldata-45.csv", show_col_types = F)) %>%
  mutate(CTYNAME = gsub(' County', '', CTYNAME),
         YEAR = as.integer(YEAR + 2007),
         WHITE = NHWA_MALE + NHWA_FEMALE,
         BLACK = NHBA_MALE + NHBA_FEMALE,
         HISPANIC = HWA_MALE + HWA_FEMALE + HBA_MALE + HBA_FEMALE + HIA_MALE + HIA_FEMALE + HAA_MALE + HAA_FEMALE + HNA_MALE + HNA_FEMALE + HIA_MALE + HIA_FEMALE,
         ASIAN = NHAA_MALE + NHAA_FEMALE,
         ISLANDER = NHNA_MALE + NHNA_FEMALE,
         NATIVE = NHIA_MALE + NHIA_FEMALE,
         MULTIRACIAL = TOM_MALE + TOM_FEMALE - HTOM_MALE - HTOM_FEMALE
         ) %>%
  filter(CTYNAME %in% counties, YEAR >= 3, AGEGRP == 0,
         !(STNAME == 'South Carolina' & CTYNAME == 'Union')) %>%
  select(STNAME, CTYNAME, YEAR, TOT_POP, WHITE, BLACK, HISPANIC, ASIAN, ISLANDER, NATIVE, MULTIRACIAL) %>%
  distinct()
ethpop <- ethpop %>%
  pivot_longer(cols = colnames(ethpop[,5:11]), names_to = 'ETHNICITY', values_to = 'POP')

# Making place of birth data frame
birthplace <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Indicator == 'Place of Birth',
         County %in% counties,
         !(Measure %in% foreign_detail)) %>%
  distinct()
birthplace <- birthplace %>% inner_join((birthplace %>% group_by(County, Year) %>% summarise(Total = sum(Numerator_value))), by = c('County', 'Year'))
`summarise()` has grouped output by 'County'. You can override using the `.groups` argument.
# Making the unemployment data frame
unemployment <- rbind(read_excel('ur_anson.xlsx', trim_ws = T) %>% mutate(County = 'Anson', Period = gsub('M', '', Period)),
                      read_excel('ur_cabarrus.xlsx', trim_ws = T) %>% mutate(County = 'Cabarrus', Period = gsub('M', '', Period)),
                      read_excel('ur_catawba.xlsx', trim_ws = T) %>% mutate(County = 'Catawba', Period = gsub('M', '', Period)),
                      read_excel('ur_chester.xlsx', trim_ws=T, skip=11)[1:266,] %>% rename(Value = 'Observation Value') %>% mutate(County = 'Chester', Period = gsub('M','',Period)) %>% select(-Label),
                      read_excel('ur_cleveland.xlsx', trim_ws = T) %>% mutate(County = 'Cleveland', Period = gsub('M', '', Period)),
                      read_excel('ur_gaston.xlsx', trim_ws = T) %>% mutate(County = 'Gaston', Period = gsub('M', '', Period)),
                      read_excel('ur_iredell.xlsx', trim_ws = T) %>% mutate(County = 'Iredell', Period = gsub('M', '', Period)),
                      read_excel('ur_lancaster.xlsx', trim_ws = T) %>% mutate(County = 'Lancaster', Period = gsub('M', '', Period)),
                      read_excel('ur_lincoln.xlsx', trim_ws = T) %>% mutate(County = 'Lincoln', Period = gsub('M', '', Period)),
                      read_excel('ur_mecklenburg.xlsx', trim_ws = T) %>% mutate(County = 'Mecklenburg', Period = gsub('M', '', Period)),
                      read_excel('ur_rowan.xlsx', trim_ws = T) %>% mutate(County = 'Rowan', Period = gsub('M', '', Period)),
                      read_excel('ur_stanly.xlsx', trim_ws=T, skip=11)[1:266,] %>% rename(Value = 'Observation Value') %>% mutate(County = 'Stanly', Period = gsub('M','',Period)) %>% select(-Label),
                      read_excel('ur_union.xlsx', trim_ws = T) %>% mutate(County = 'Union', Period = gsub('M', '', Period)),
                      read_excel('ur_york.xlsx', trim_ws = T) %>% mutate(County = 'York', Period = gsub('M', '', Period))) %>%
  mutate(Year = as.integer(Year),
         Period = as.integer(Period),
         Date = as.Date(paste(Year,'-',Period, '-01', sep = '')),
         Value = Value/100) %>%
  rename(Month = Period,
         Unemployment = Value)

# Make income data frame
income <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Indicator == 'Income & Earnings',
         County %in% counties,
         Measure != 'Household Income: Total') %>%
  distinct()
income <- income %>% inner_join((income %>% group_by(County, Year) %>% summarise(Total = sum(Numerator_value))), by = c('County', 'Year'))
`summarise()` has grouped output by 'County'. You can override using the `.groups` argument.
# Make education attainment data frame
education <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Indicator == 'Educational Attainment',
         County %in% counties,
         Measure %in% attainment_lvl) %>%
  distinct()
education <- education %>% inner_join((education %>% group_by(County, Year) %>% summarise(Total = sum(Numerator_value))), by = c('County', 'Year')) %>%
  mutate(
    Order = as.factor(case_when(
      Measure == 'Highest Degree: Less than a High School Diploma' ~ 1,
      Measure == 'Highest Degree: High School Diploma' ~ 2,
      Measure == 'Highest Degree: Some College, No Degree' ~ 3,
      Measure == "Highest Degree: Associate's Degree" ~ 4,
      Measure == "Highest Degree: Bachelor's Degree" ~ 5,
      Measure == "Highest Degree: Graduate or Professional Degree" ~ 6)),
    Measure = gsub("Highest Degree: ","",Measure))
`summarise()` has grouped output by 'County'. You can override using the `.groups` argument.
# Make health care coverage data frame
coverage <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Indicator == 'Health Care Coverage',
         County %in% counties)
# Make housing age data frame
housing <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County),
         diff = Year-Numerator_value) %>%
  filter(Indicator == 'Housing Stock',
         County %in% counties)
# Make poverty figures data frame
poverty <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Measure == 'Individuals in Poverty',
         Theme == 'Social Well-Being',
         County %in% counties)
# Make transportation means data frame
transportation <- read.csv('Values.csv') %>%
  mutate(County = gsub(' County, North Carolina', '', County),
         County = gsub(' County, South Carolina', '', County)) %>%
  filter(Theme == 'Transportation',
         Measure != 'Commuting Means Total',
         County %in% counties)

Demographics

Population

plot_ly(countypop %>% filter(YEAR == 2019), x = ~POPESTIMATE, y = ~CTYNAME, type = 'bar', color = ~CTYNAME, colors = color_a, orientation = 'h')

plot_ly(countypop, x=~YEAR, y=~CHANGE, color=~CTYNAME, type='scatter', mode='lines', colors=color_a)

Age & Gender

plot_ly(pop_age_gender %>% filter(YEAR == 2017, CTYNAME == 'Charlotte Region'),
        y=~DEMO, x=~PERCENTAGE,
        type='bar', color=~GENDER)

Race & Ethnicity

plot_ly(ethpop %>% filter(YEAR == 2019),
        y=~CTYNAME, x=~POP/TOT_POP, color=~ETHNICITY,
        type='bar') %>%
  layout(barmode = 'stack')

Place of Birth

plot_ly(birthplace %>% filter(Year == 2019),
        y=~County, x=~Numerator_value/Total, color=~Measure,
        type='bar') %>%
  layout(barmode = 'stack')

Economy

Unemployment

plot_ly(unemployment, x=~Date, y=~Unemployment, color=~County, colors=color_a, type='scatter', mode='lines')

plot_ly(unemployment %>% filter(Year==2015, Month==6), x=~Unemployment, y=~County, color=~County, colors=color_a, type='bar')

6/21 Up to this point has been done in the shiny app

Income

#### DFs from Values.csv are missing Anson, Chester, and Stanly Counties
plot_ly(income %>% filter(Year == 2014), y=~County, x=~(Numerator_value/Total), color=~Measure, type='bar') %>%
  layout(barmode='stack')

Education

Educational Attainment

plot_ly(education %>% group_by(Year, Measure, County) %>%
  summarise(Numerator = sum(Numerator_value),
            Denominator = mean(Total)) %>% filter(Year == 2018, Measure == 'High School Diploma'), y=~County, color=~County, colors=color_na, x=~(Numerator/Denominator), type='bar')
`summarise()` has grouped output by 'Year', 'Measure'. You can override using the `.groups` argument.

Health

Health Care Coverage

Housing

Housing Age

housing %>% filter(Year == 2017) %>%
  ggplot(aes(x= County, y = Year-Numerator_value, fill = County)) +
  geom_col() +
  coord_flip()

# axis is giving double the true value
plot_ly(housing %>% filter(Year == 2014), y=~County, x=~diff,
        color=~County, colors=color_na, type='bar')

Social Well-Being

Poverty

plot_ly(poverty %>% filter(Year==2014),
        y=~County, x=~Numerator_value/Denominator_value,
        color=~County, colors=color_na, type='bar')

Transportation

##Commuting Modes

# Way too many missing values to create a substantive visualization.
transportation %>% filter(Year == 2014) %>%
  ggplot(aes(x = County, y = Numerator_value, fill = Measure, position = Measure)) +
  geom_col(position = 'dodge') +
  scale_y_continuous(labels = comma) +
  coord_flip()
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIExvYWQgUGFja2FnZXMNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCg0KIyBNYWtpbmcgRGF0YWZyYW1lcw0KYGBge3J9DQpjb2xvcl9hIDwtIGMoIiM1OGI1ZTEiLCIjMWM1YjVhIiwiIzQ2ZWJkYyIsIiMxZjQxOTYiLCIjZTI4ZGUyIiwiIzgxOGJkNyIsIiNlNGNjZjEiLCIjODIxODVmIiwiI2Y4NDliNiIsIiMwMDAwMDAiLCIjNWUzNGJjIiwiI2I3ZDE2NSIsIiMzMGQ1MmUiLCIjZmY1MzU3IikNCmNvbG9yX25hIDwtIGMoIiMxYzViNWEiLCIjNDZlYmRjIiwiI2UyOGRlMiIsIiM4MThiZDciLCIjZTRjY2YxIiwiIzgyMTg1ZiIsIiNmODQ5YjYiLCIjMDAwMDAwIiwiIzVlMzRiYyIsIiMzMGQ1MmUiLCIjZmY1MzU3IikNCmNvdW50aWVzIDwtIGMoJ0Fuc29uJywgJ0NhYmFycnVzJywgJ0NhdGF3YmEnLCAnQ2hlc3RlcicsICdDbGV2ZWxhbmQnLCAnR2FzdG9uJywgJ0lyZWRlbGwnLCAnTGFuY2FzdGVyJywgJ0xpbmNvbG4nLCAnTWVja2xlbmJ1cmcnLCAnUm93YW4nLCAnU3Rhbmx5JywgJ1VuaW9uJywgJ1lvcmsnKQ0KYXR0YWlubWVudF9sdmwgPC0gYygnSGlnaGVzdCBEZWdyZWU6IExlc3MgdGhhbiBhIEhpZ2ggU2Nob29sIERpcGxvbWEnLCAnSGlnaGVzdCBEZWdyZWU6IEhpZ2ggU2Nob29sIERpcGxvbWEnLCAnSGlnaGVzdCBEZWdyZWU6IFNvbWUgQ29sbGVnZSwgTm8gRGVncmVlJywgIkhpZ2hlc3QgRGVncmVlOiBBc3NvY2lhdGUncyBEZWdyZWUiLCAiSGlnaGVzdCBEZWdyZWU6IEJhY2hlbG9yJ3MgRGVncmVlIiwgIkhpZ2hlc3QgRGVncmVlOiBHcmFkdWF0ZSBvciBQcm9mZXNzaW9uYWwgRGVncmVlIikNCmZvcmVpZ25fZGV0YWlsIDwtIGMoJ0ZvcmVpZ24tQm9ybjogQWZyaWNhJywgJ0ZvcmVpZ24tQm9ybjogQXNpYScsICdGb3JlaWduLUJvcm46IEV1cm9wZScsICdGb3JlaWduLUJvcm46IExhdGluIEFtZXJpY2EnLCAnUGxhY2Ugb2YgQmlydGggVG90YWwnKQ0KDQpjb3VudHlwb3AgPC0gcmJpbmQocmVhZF9jc3YoImNjLWVzdDIwMTktYWdlc2V4LTM3LmNzdiIsIHNob3dfY29sX3R5cGVzID0gRiksDQogICAgICAgICAgICAgICAgICAgcmVhZF9jc3YoImNjLWVzdDIwMTktYWdlc2V4LTQ1LmNzdiIsIHNob3dfY29sX3R5cGVzID0gRikpICU+JQ0KICBzZWxlY3QoLVNVTUxFViwgLVNUQVRFLCAtQ09VTlRZKSAlPiUNCiAgbXV0YXRlKENUWU5BTUUgPSBnc3ViKCcgQ291bnR5JywgJycsIENUWU5BTUUpLA0KICAgICAgICAgWUVBUiA9IGFzLmludGVnZXIoWUVBUiArIDIwMDcpKSAlPiUNCiAgZmlsdGVyKENUWU5BTUUgJWluJSBjb3VudGllcywgWUVBUiA+PSAyMDEwLA0KICAgICAgICAgIShTVE5BTUUgPT0gJ1NvdXRoIENhcm9saW5hJyAmIENUWU5BTUUgPT0gJ1VuaW9uJykpICU+JQ0KICBkaXN0aW5jdCgpDQojIFllYXIgMyBpcyAyMDEwLCBZZWFyIDEyIGlzIDIwMTkNCg0KIyBNYWtpbmcgQ2hhcmxvdHRlIFJlZ2lvbg0KY3IgPC0gY291bnR5cG9wWzE6MTAsXSAlPiUNCiAgbXV0YXRlKENUWU5BTUUgPSAnQ2hhcmxvdHRlIFJlZ2lvbicpDQpmb3IoaSBpbiA0Omxlbmd0aChjb2xuYW1lcyhjb3VudHlwb3ApKSkgew0KICBmb3IoaiBpbiAxOjEwKXsNCiAgICBjcltqLGldIDwtIHN1bSgoY291bnR5cG9wICU+JSBmaWx0ZXIoWUVBUiA9PSBqKzIwMDkpKVtpXSkNCiAgfQ0KfQ0KDQojIE1ha2luZyBBZ2UgJiBHZW5kZXIgZGF0YSBmcmFtZQ0KcG9wX2FnZV9nZW5kZXIgPC0gcmJpbmQoY291bnR5cG9wLCBjcikNCmNvdW50eXBvcCA8LSBjciAlPiUgdHJhbnNtdXRlKFlFQVIgPSBZRUFSLCBDSEFSTE9UVEVQT1AgPSBQT1BFU1RJTUFURSkgJT4lIHJpZ2h0X2pvaW4oY291bnR5cG9wLCBieSA9ICdZRUFSJykgJT4lIG11dGF0ZShQUk9QT1JUSU9OID0gUE9QRVNUSU1BVEUgLyBDSEFSTE9UVEVQT1ApICU+JQ0KICBncm91cF9ieShDVFlOQU1FKSAlPiUNCiAgbXV0YXRlKENIQU5HRSA9IGlmZWxzZShZRUFSID09IDIwMTAsIDAsIFBPUEVTVElNQVRFL2xhZyhQT1BFU1RJTUFURSwgZGVmYXVsdCA9IGZpcnN0KFlFQVIpKSAtIDEpKSAlPiUNCiAgdW5ncm91cCgpDQoNCnBvcF9hZ2VfZ2VuZGVyIDwtIHBvcF9hZ2VfZ2VuZGVyICU+JQ0KICBzZWxlY3QoLWNvbnRhaW5zKCdfVE9UJyksIC1QT1BFU1RfRkVNLCAtUE9QRVNUX01BTEUsIC1BR0UxNlBMVVNfTUFMRSwgLUFHRTE2UExVU19GRU0sIC1BR0UxOFBMVVNfRkVNLCAtQUdFMThQTFVTX01BTEUsIC1VTkRFUjVfRkVNLCAtVU5ERVI1X01BTEUsIC1BR0UxNTQ0X0ZFTSwgLUFHRTE1NDRfTUFMRSwgLU1FRElBTl9BR0VfRkVNLCAtTUVESUFOX0FHRV9NQUxFLCAtQUdFNjVQTFVTX0ZFTSwtQUdFNjVQTFVTX01BTEUsIC1BR0U1MTNfRkVNLCAtQUdFNTEzX01BTEUsIC1BR0U0NTY0X0ZFTSwgLUFHRTQ1NjRfTUFMRSwgLUFHRTI1NDRfRkVNLCAtQUdFMjU0NF9NQUxFLCAtQUdFMTgyNF9GRU0sIC1BR0UxODI0X01BTEUsIC1BR0UxNDE3X0ZFTSwgLUFHRTE0MTdfTUFMRSkgJT4lDQogIHJlbmFtZShBR0UwMDRfRkVNID0gQUdFMDRfRkVNLCBBR0UwMDRfTUFMRSA9IEFHRTA0X01BTEUsIEFHRTA1MDlfTUFMRSA9IEFHRTU5X01BTEUsIEFHRTA1MDlfRkVNID0gQUdFNTlfRkVNKQ0KcG9wX2FnZV9nZW5kZXIgPC0gcG9wX2FnZV9nZW5kZXIgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gY29sbmFtZXMocG9wX2FnZV9nZW5kZXJbLDU6NDBdKSwgbmFtZXNfdG8gPSAnREVNTycsIHZhbHVlc190byA9ICdQT1AnKSAlPiUNCiAgbXV0YXRlKFBFUkNFTlRBR0UgPSBQT1AvUE9QRVNUSU1BVEUpDQpwb3BfYWdlX2dlbmRlciA8LSBwb3BfYWdlX2dlbmRlciAlPiUNCiAgbXV0YXRlKEdFTkRFUiA9IGFzLmZhY3RvcihpZmVsc2UoZ3JlcGwoJ01BTEUnLCBwb3BfYWdlX2dlbmRlciRERU1PKSwnTUFMRScsJ0ZFTUFMRScpKSwNCiAgICAgICAgIERFTU8gPSBnc3ViKCdfRkVNJywnJywgREVNTyksDQogICAgICAgICBERU1PID0gZ3N1YignX01BTEUnLCcnLCBERU1PKSwNCiAgICAgICAgIERFTU8gPSBjYXNlX3doZW4oREVNTyA9PSAnQUdFMDA0JyB+ICcwLTA0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFMDUwOScgfiAnMDUtMDknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0UxMDE0JyB+ICcxMC0xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTE1MTknIH4gJzE1LTE5JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFMjAyNCcgfiAnMjAtMjQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0UyNTI5JyB+ICcyNS0yOScsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTMwMzQnIH4gJzMwLTM0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFMzUzOScgfiAnMzUtMzknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0U0MDQ0JyB+ICc0MC00NCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTQ1NDknIH4gJzQ1LTQ5JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFNTA1NCcgfiAnNTAtNTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0U1NTU5JyB+ICc1NS01OScsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTYwNjQnIH4gJzYwLTY0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFNjU2OScgfiAnNjUtNjknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0U3MDc0JyB+ICc3MC03NCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgIERFTU8gPT0gJ0FHRTc1NzknIH4gJzc1LTc5JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgREVNTyA9PSAnQUdFODA4NCcgfiAnODAtODQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBERU1PID09ICdBR0U4NVBMVVMnIH4gJzg1IGFuZCBPdmVyJykpDQoNCiMgTWFraW5nIGV0aG5pY2l0eSBkYXRhIGZyYW1lDQpldGhwb3AgPC0gcmJpbmQocmVhZF9jc3YoImNjLWVzdDIwMTktYWxsZGF0YS0zNy5jc3YiLCBzaG93X2NvbF90eXBlcyA9IEYpLA0KICAgICAgICAgICAgICAgICAgIHJlYWRfY3N2KCJjYy1lc3QyMDE5LWFsbGRhdGEtNDUuY3N2Iiwgc2hvd19jb2xfdHlwZXMgPSBGKSkgJT4lDQogIG11dGF0ZShDVFlOQU1FID0gZ3N1YignIENvdW50eScsICcnLCBDVFlOQU1FKSwNCiAgICAgICAgIFlFQVIgPSBhcy5pbnRlZ2VyKFlFQVIgKyAyMDA3KSwNCiAgICAgICAgIFdISVRFID0gTkhXQV9NQUxFICsgTkhXQV9GRU1BTEUsDQogICAgICAgICBCTEFDSyA9IE5IQkFfTUFMRSArIE5IQkFfRkVNQUxFLA0KICAgICAgICAgSElTUEFOSUMgPSBIV0FfTUFMRSArIEhXQV9GRU1BTEUgKyBIQkFfTUFMRSArIEhCQV9GRU1BTEUgKyBISUFfTUFMRSArIEhJQV9GRU1BTEUgKyBIQUFfTUFMRSArIEhBQV9GRU1BTEUgKyBITkFfTUFMRSArIEhOQV9GRU1BTEUgKyBISUFfTUFMRSArIEhJQV9GRU1BTEUsDQogICAgICAgICBBU0lBTiA9IE5IQUFfTUFMRSArIE5IQUFfRkVNQUxFLA0KICAgICAgICAgSVNMQU5ERVIgPSBOSE5BX01BTEUgKyBOSE5BX0ZFTUFMRSwNCiAgICAgICAgIE5BVElWRSA9IE5ISUFfTUFMRSArIE5ISUFfRkVNQUxFLA0KICAgICAgICAgTVVMVElSQUNJQUwgPSBUT01fTUFMRSArIFRPTV9GRU1BTEUgLSBIVE9NX01BTEUgLSBIVE9NX0ZFTUFMRQ0KICAgICAgICAgKSAlPiUNCiAgZmlsdGVyKENUWU5BTUUgJWluJSBjb3VudGllcywgWUVBUiA+PSAzLCBBR0VHUlAgPT0gMCwNCiAgICAgICAgICEoU1ROQU1FID09ICdTb3V0aCBDYXJvbGluYScgJiBDVFlOQU1FID09ICdVbmlvbicpKSAlPiUNCiAgc2VsZWN0KFNUTkFNRSwgQ1RZTkFNRSwgWUVBUiwgVE9UX1BPUCwgV0hJVEUsIEJMQUNLLCBISVNQQU5JQywgQVNJQU4sIElTTEFOREVSLCBOQVRJVkUsIE1VTFRJUkFDSUFMKSAlPiUNCiAgZGlzdGluY3QoKQ0KZXRocG9wIDwtIGV0aHBvcCAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb2xuYW1lcyhldGhwb3BbLDU6MTFdKSwgbmFtZXNfdG8gPSAnRVRITklDSVRZJywgdmFsdWVzX3RvID0gJ1BPUCcpDQoNCiMgTWFraW5nIHBsYWNlIG9mIGJpcnRoIGRhdGEgZnJhbWUNCmJpcnRocGxhY2UgPC0gcmVhZC5jc3YoJ1ZhbHVlcy5jc3YnKSAlPiUNCiAgbXV0YXRlKENvdW50eSA9IGdzdWIoJyBDb3VudHksIE5vcnRoIENhcm9saW5hJywgJycsIENvdW50eSksDQogICAgICAgICBDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBTb3V0aCBDYXJvbGluYScsICcnLCBDb3VudHkpKSAlPiUNCiAgZmlsdGVyKEluZGljYXRvciA9PSAnUGxhY2Ugb2YgQmlydGgnLA0KICAgICAgICAgQ291bnR5ICVpbiUgY291bnRpZXMsDQogICAgICAgICAhKE1lYXN1cmUgJWluJSBmb3JlaWduX2RldGFpbCkpICU+JQ0KICBkaXN0aW5jdCgpDQpiaXJ0aHBsYWNlIDwtIGJpcnRocGxhY2UgJT4lIGlubmVyX2pvaW4oKGJpcnRocGxhY2UgJT4lIGdyb3VwX2J5KENvdW50eSwgWWVhcikgJT4lIHN1bW1hcmlzZShUb3RhbCA9IHN1bShOdW1lcmF0b3JfdmFsdWUpKSksIGJ5ID0gYygnQ291bnR5JywgJ1llYXInKSkNCg0KIyBNYWtpbmcgdGhlIHVuZW1wbG95bWVudCBkYXRhIGZyYW1lDQp1bmVtcGxveW1lbnQgPC0gcmJpbmQocmVhZF9leGNlbCgndXJfYW5zb24ueGxzeCcsIHRyaW1fd3MgPSBUKSAlPiUgbXV0YXRlKENvdW50eSA9ICdBbnNvbicsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfY2FiYXJydXMueGxzeCcsIHRyaW1fd3MgPSBUKSAlPiUgbXV0YXRlKENvdW50eSA9ICdDYWJhcnJ1cycsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfY2F0YXdiYS54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0NhdGF3YmEnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX2NoZXN0ZXIueGxzeCcsIHRyaW1fd3M9VCwgc2tpcD0xMSlbMToyNjYsXSAlPiUgcmVuYW1lKFZhbHVlID0gJ09ic2VydmF0aW9uIFZhbHVlJykgJT4lIG11dGF0ZShDb3VudHkgPSAnQ2hlc3RlcicsIFBlcmlvZCA9IGdzdWIoJ00nLCcnLFBlcmlvZCkpICU+JSBzZWxlY3QoLUxhYmVsKSwNCiAgICAgICAgICAgICAgICAgICAgICByZWFkX2V4Y2VsKCd1cl9jbGV2ZWxhbmQueGxzeCcsIHRyaW1fd3MgPSBUKSAlPiUgbXV0YXRlKENvdW50eSA9ICdDbGV2ZWxhbmQnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX2dhc3Rvbi54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0dhc3RvbicsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfaXJlZGVsbC54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0lyZWRlbGwnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX2xhbmNhc3Rlci54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0xhbmNhc3RlcicsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfbGluY29sbi54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ0xpbmNvbG4nLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX21lY2tsZW5idXJnLnhsc3gnLCB0cmltX3dzID0gVCkgJT4lIG11dGF0ZShDb3VudHkgPSAnTWVja2xlbmJ1cmcnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX3Jvd2FuLnhsc3gnLCB0cmltX3dzID0gVCkgJT4lIG11dGF0ZShDb3VudHkgPSAnUm93YW4nLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoJ3VyX3N0YW5seS54bHN4JywgdHJpbV93cz1ULCBza2lwPTExKVsxOjI2NixdICU+JSByZW5hbWUoVmFsdWUgPSAnT2JzZXJ2YXRpb24gVmFsdWUnKSAlPiUgbXV0YXRlKENvdW50eSA9ICdTdGFubHknLCBQZXJpb2QgPSBnc3ViKCdNJywnJyxQZXJpb2QpKSAlPiUgc2VsZWN0KC1MYWJlbCksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfdW5pb24ueGxzeCcsIHRyaW1fd3MgPSBUKSAlPiUgbXV0YXRlKENvdW50eSA9ICdVbmlvbicsIFBlcmlvZCA9IGdzdWIoJ00nLCAnJywgUGVyaW9kKSksDQogICAgICAgICAgICAgICAgICAgICAgcmVhZF9leGNlbCgndXJfeW9yay54bHN4JywgdHJpbV93cyA9IFQpICU+JSBtdXRhdGUoQ291bnR5ID0gJ1lvcmsnLCBQZXJpb2QgPSBnc3ViKCdNJywgJycsIFBlcmlvZCkpKSAlPiUNCiAgbXV0YXRlKFllYXIgPSBhcy5pbnRlZ2VyKFllYXIpLA0KICAgICAgICAgUGVyaW9kID0gYXMuaW50ZWdlcihQZXJpb2QpLA0KICAgICAgICAgRGF0ZSA9IGFzLkRhdGUocGFzdGUoWWVhciwnLScsUGVyaW9kLCAnLTAxJywgc2VwID0gJycpKSwNCiAgICAgICAgIFZhbHVlID0gVmFsdWUvMTAwKSAlPiUNCiAgcmVuYW1lKE1vbnRoID0gUGVyaW9kLA0KICAgICAgICAgVW5lbXBsb3ltZW50ID0gVmFsdWUpDQoNCiMgTWFrZSBpbmNvbWUgZGF0YSBmcmFtZQ0KaW5jb21lIDwtIHJlYWQuY3N2KCdWYWx1ZXMuY3N2JykgJT4lDQogIG11dGF0ZShDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBOb3J0aCBDYXJvbGluYScsICcnLCBDb3VudHkpLA0KICAgICAgICAgQ291bnR5ID0gZ3N1YignIENvdW50eSwgU291dGggQ2Fyb2xpbmEnLCAnJywgQ291bnR5KSkgJT4lDQogIGZpbHRlcihJbmRpY2F0b3IgPT0gJ0luY29tZSAmIEVhcm5pbmdzJywNCiAgICAgICAgIENvdW50eSAlaW4lIGNvdW50aWVzLA0KICAgICAgICAgTWVhc3VyZSAhPSAnSG91c2Vob2xkIEluY29tZTogVG90YWwnKSAlPiUNCiAgZGlzdGluY3QoKQ0KaW5jb21lIDwtIGluY29tZSAlPiUgaW5uZXJfam9pbigoaW5jb21lICU+JSBncm91cF9ieShDb3VudHksIFllYXIpICU+JSBzdW1tYXJpc2UoVG90YWwgPSBzdW0oTnVtZXJhdG9yX3ZhbHVlKSkpLCBieSA9IGMoJ0NvdW50eScsICdZZWFyJykpDQoNCiMgTWFrZSBlZHVjYXRpb24gYXR0YWlubWVudCBkYXRhIGZyYW1lDQplZHVjYXRpb24gPC0gcmVhZC5jc3YoJ1ZhbHVlcy5jc3YnKSAlPiUNCiAgbXV0YXRlKENvdW50eSA9IGdzdWIoJyBDb3VudHksIE5vcnRoIENhcm9saW5hJywgJycsIENvdW50eSksDQogICAgICAgICBDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBTb3V0aCBDYXJvbGluYScsICcnLCBDb3VudHkpKSAlPiUNCiAgZmlsdGVyKEluZGljYXRvciA9PSAnRWR1Y2F0aW9uYWwgQXR0YWlubWVudCcsDQogICAgICAgICBDb3VudHkgJWluJSBjb3VudGllcywNCiAgICAgICAgIE1lYXN1cmUgJWluJSBhdHRhaW5tZW50X2x2bCkgJT4lDQogIGRpc3RpbmN0KCkNCmVkdWNhdGlvbiA8LSBlZHVjYXRpb24gJT4lIGlubmVyX2pvaW4oKGVkdWNhdGlvbiAlPiUgZ3JvdXBfYnkoQ291bnR5LCBZZWFyKSAlPiUgc3VtbWFyaXNlKFRvdGFsID0gc3VtKE51bWVyYXRvcl92YWx1ZSkpKSwgYnkgPSBjKCdDb3VudHknLCAnWWVhcicpKSAlPiUNCiAgbXV0YXRlKA0KICAgIE9yZGVyID0gYXMuZmFjdG9yKGNhc2Vfd2hlbigNCiAgICAgIE1lYXN1cmUgPT0gJ0hpZ2hlc3QgRGVncmVlOiBMZXNzIHRoYW4gYSBIaWdoIFNjaG9vbCBEaXBsb21hJyB+IDEsDQogICAgICBNZWFzdXJlID09ICdIaWdoZXN0IERlZ3JlZTogSGlnaCBTY2hvb2wgRGlwbG9tYScgfiAyLA0KICAgICAgTWVhc3VyZSA9PSAnSGlnaGVzdCBEZWdyZWU6IFNvbWUgQ29sbGVnZSwgTm8gRGVncmVlJyB+IDMsDQogICAgICBNZWFzdXJlID09ICJIaWdoZXN0IERlZ3JlZTogQXNzb2NpYXRlJ3MgRGVncmVlIiB+IDQsDQogICAgICBNZWFzdXJlID09ICJIaWdoZXN0IERlZ3JlZTogQmFjaGVsb3IncyBEZWdyZWUiIH4gNSwNCiAgICAgIE1lYXN1cmUgPT0gIkhpZ2hlc3QgRGVncmVlOiBHcmFkdWF0ZSBvciBQcm9mZXNzaW9uYWwgRGVncmVlIiB+IDYpKSwNCiAgICBNZWFzdXJlID0gZ3N1YigiSGlnaGVzdCBEZWdyZWU6ICIsIiIsTWVhc3VyZSkpDQojIE1ha2UgaGVhbHRoIGNhcmUgY292ZXJhZ2UgZGF0YSBmcmFtZQ0KY292ZXJhZ2UgPC0gcmVhZC5jc3YoJ1ZhbHVlcy5jc3YnKSAlPiUNCiAgbXV0YXRlKENvdW50eSA9IGdzdWIoJyBDb3VudHksIE5vcnRoIENhcm9saW5hJywgJycsIENvdW50eSksDQogICAgICAgICBDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBTb3V0aCBDYXJvbGluYScsICcnLCBDb3VudHkpKSAlPiUNCiAgZmlsdGVyKEluZGljYXRvciA9PSAnSGVhbHRoIENhcmUgQ292ZXJhZ2UnLA0KICAgICAgICAgQ291bnR5ICVpbiUgY291bnRpZXMpDQojIE1ha2UgaG91c2luZyBhZ2UgZGF0YSBmcmFtZQ0KaG91c2luZyA8LSByZWFkLmNzdignVmFsdWVzLmNzdicpICU+JQ0KICBtdXRhdGUoQ291bnR5ID0gZ3N1YignIENvdW50eSwgTm9ydGggQ2Fyb2xpbmEnLCAnJywgQ291bnR5KSwNCiAgICAgICAgIENvdW50eSA9IGdzdWIoJyBDb3VudHksIFNvdXRoIENhcm9saW5hJywgJycsIENvdW50eSksDQogICAgICAgICBkaWZmID0gWWVhci1OdW1lcmF0b3JfdmFsdWUpICU+JQ0KICBmaWx0ZXIoSW5kaWNhdG9yID09ICdIb3VzaW5nIFN0b2NrJywNCiAgICAgICAgIENvdW50eSAlaW4lIGNvdW50aWVzKQ0KIyBNYWtlIHBvdmVydHkgZmlndXJlcyBkYXRhIGZyYW1lDQpwb3ZlcnR5IDwtIHJlYWQuY3N2KCdWYWx1ZXMuY3N2JykgJT4lDQogIG11dGF0ZShDb3VudHkgPSBnc3ViKCcgQ291bnR5LCBOb3J0aCBDYXJvbGluYScsICcnLCBDb3VudHkpLA0KICAgICAgICAgQ291bnR5ID0gZ3N1YignIENvdW50eSwgU291dGggQ2Fyb2xpbmEnLCAnJywgQ291bnR5KSkgJT4lDQogIGZpbHRlcihNZWFzdXJlID09ICdJbmRpdmlkdWFscyBpbiBQb3ZlcnR5JywNCiAgICAgICAgIFRoZW1lID09ICdTb2NpYWwgV2VsbC1CZWluZycsDQogICAgICAgICBDb3VudHkgJWluJSBjb3VudGllcykNCiMgTWFrZSB0cmFuc3BvcnRhdGlvbiBtZWFucyBkYXRhIGZyYW1lDQp0cmFuc3BvcnRhdGlvbiA8LSByZWFkLmNzdignVmFsdWVzLmNzdicpICU+JQ0KICBtdXRhdGUoQ291bnR5ID0gZ3N1YignIENvdW50eSwgTm9ydGggQ2Fyb2xpbmEnLCAnJywgQ291bnR5KSwNCiAgICAgICAgIENvdW50eSA9IGdzdWIoJyBDb3VudHksIFNvdXRoIENhcm9saW5hJywgJycsIENvdW50eSkpICU+JQ0KICBmaWx0ZXIoVGhlbWUgPT0gJ1RyYW5zcG9ydGF0aW9uJywNCiAgICAgICAgIE1lYXN1cmUgIT0gJ0NvbW11dGluZyBNZWFucyBUb3RhbCcsDQogICAgICAgICBDb3VudHkgJWluJSBjb3VudGllcykNCmBgYA0KDQoNCiMgRGVtb2dyYXBoaWNzDQojIyBQb3B1bGF0aW9uDQpgYGB7cn0NCnBsb3RfbHkoY291bnR5cG9wICU+JSBmaWx0ZXIoWUVBUiA9PSAyMDE5KSwgeCA9IH5QT1BFU1RJTUFURSwgeSA9IH5DVFlOQU1FLCB0eXBlID0gJ2JhcicsIGNvbG9yID0gfkNUWU5BTUUsIGNvbG9ycyA9IGNvbG9yX2EsIG9yaWVudGF0aW9uID0gJ2gnKQ0KDQpwbG90X2x5KGNvdW50eXBvcCwgeD1+WUVBUiwgeT1+Q0hBTkdFLCBjb2xvcj1+Q1RZTkFNRSwgdHlwZT0nc2NhdHRlcicsIG1vZGU9J2xpbmVzJywgY29sb3JzPWNvbG9yX2EpDQpgYGANCg0KIyMgQWdlICYgR2VuZGVyDQpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aD0gMTAsIHdhcm5pbmc9RkFMU0V9DQpwbG90X2x5KHBvcF9hZ2VfZ2VuZGVyICU+JSBmaWx0ZXIoWUVBUiA9PSAyMDE3LCBDVFlOQU1FID09ICdDaGFybG90dGUgUmVnaW9uJyksDQogICAgICAgIHk9fkRFTU8sIHg9flBFUkNFTlRBR0UsDQogICAgICAgIHR5cGU9J2JhcicsIGNvbG9yPX5HRU5ERVIpDQpgYGANCg0KIyMgUmFjZSAmIEV0aG5pY2l0eQ0KYGBge3J9DQpwbG90X2x5KGV0aHBvcCAlPiUgZmlsdGVyKFlFQVIgPT0gMjAxOSksDQogICAgICAgIHk9fkNUWU5BTUUsIHg9flBPUC9UT1RfUE9QLCBjb2xvcj1+RVRITklDSVRZLA0KICAgICAgICB0eXBlPSdiYXInKSAlPiUNCiAgbGF5b3V0KGJhcm1vZGUgPSAnc3RhY2snKQ0KYGBgDQoNCiMjIFBsYWNlIG9mIEJpcnRoDQpgYGB7cn0NCnBsb3RfbHkoYmlydGhwbGFjZSAlPiUgZmlsdGVyKFllYXIgPT0gMjAxOSksDQogICAgICAgIHk9fkNvdW50eSwgeD1+TnVtZXJhdG9yX3ZhbHVlL1RvdGFsLCBjb2xvcj1+TWVhc3VyZSwNCiAgICAgICAgdHlwZT0nYmFyJykgJT4lDQogIGxheW91dChiYXJtb2RlID0gJ3N0YWNrJykNCmBgYA0KDQoNCg0KIyBFY29ub215DQojIyBVbmVtcGxveW1lbnQNCmBgYHtyfQ0KcGxvdF9seSh1bmVtcGxveW1lbnQsIHg9fkRhdGUsIHk9flVuZW1wbG95bWVudCwgY29sb3I9fkNvdW50eSwgY29sb3JzPWNvbG9yX2EsIHR5cGU9J3NjYXR0ZXInLCBtb2RlPSdsaW5lcycpDQoNCnBsb3RfbHkodW5lbXBsb3ltZW50ICU+JSBmaWx0ZXIoWWVhcj09MjAxNSwgTW9udGg9PTYpLCB4PX5VbmVtcGxveW1lbnQsIHk9fkNvdW50eSwgY29sb3I9fkNvdW50eSwgY29sb3JzPWNvbG9yX2EsIHR5cGU9J2JhcicpDQpgYGANCg0KIyMjIyMjIyMjIyMjIyMjIyAgIDYvMjEgVXAgdG8gdGhpcyBwb2ludCBoYXMgYmVlbiBkb25lIGluIHRoZSBzaGlueSBhcHAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KDQojIyBJbmNvbWUNCmBgYHtyfQ0KIyMjIyBERnMgZnJvbSBWYWx1ZXMuY3N2IGFyZSBtaXNzaW5nIEFuc29uLCBDaGVzdGVyLCBhbmQgU3Rhbmx5IENvdW50aWVzDQpwbG90X2x5KGluY29tZSAlPiUgZmlsdGVyKFllYXIgPT0gMjAxNCksIHk9fkNvdW50eSwgeD1+KE51bWVyYXRvcl92YWx1ZS9Ub3RhbCksIGNvbG9yPX5NZWFzdXJlLCB0eXBlPSdiYXInKSAlPiUNCiAgbGF5b3V0KGJhcm1vZGU9J3N0YWNrJykNCmBgYA0KDQojIEVkdWNhdGlvbg0KIyMgRWR1Y2F0aW9uYWwgQXR0YWlubWVudA0KYGBge3J9DQpwbG90X2x5KGVkdWNhdGlvbiAlPiUgZ3JvdXBfYnkoWWVhciwgTWVhc3VyZSwgQ291bnR5KSAlPiUNCiAgc3VtbWFyaXNlKE51bWVyYXRvciA9IHN1bShOdW1lcmF0b3JfdmFsdWUpLA0KICAgICAgICAgICAgRGVub21pbmF0b3IgPSBtZWFuKFRvdGFsKSkgJT4lIGZpbHRlcihZZWFyID09IDIwMTgsIE1lYXN1cmUgPT0gJ0hpZ2ggU2Nob29sIERpcGxvbWEnKSwgeT1+Q291bnR5LCBjb2xvcj1+Q291bnR5LCBjb2xvcnM9Y29sb3JfbmEsIHg9fihOdW1lcmF0b3IvRGVub21pbmF0b3IpLCB0eXBlPSdiYXInKQ0KYGBgDQoNCiMgSGVhbHRoDQojIyBIZWFsdGggQ2FyZSBDb3ZlcmFnZQ0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpwbG90X2x5KGNvdmVyYWdlICU+JQ0KICAgICAgICAgZ3JvdXBfYnkoWWVhciwgQ291bnR5LCBNZWFzdXJlKSAlPiUNCiAgICAgICAgIHN1bW1hcmlzZShhZGRlZD1zdW0oTnVtZXJhdG9yX3ZhbHVlKSkgJT4lDQogICAgICAgICBmaWx0ZXIoWWVhcj09MjAxNiwgIShNZWFzdXJlICVpbiUgYygiSGVhbHRoIEluc3VyYW5jZSBUb3RhbCIpKSksDQogICAgICAgeT1+Q291bnR5LCB4PX5hZGRlZCwgdHlwZT0nYmFyJywgY29sb3I9fk1lYXN1cmUpDQoNCnBsb3RfbHkoY292ZXJhZ2UgJT4lDQogICAgICAgICBncm91cF9ieShZZWFyLCBDb3VudHksIE1lYXN1cmUpICU+JQ0KICAgICAgICAgc3VtbWFyaXNlKGFkZGVkPXN1bShOdW1lcmF0b3JfdmFsdWUpKSAlPiUNCiAgICAgICAgIGZpbHRlcihZZWFyPT0yMDE2LCBNZWFzdXJlPT0nQ2hpbGRyZW4gd2l0aG91dCBIZWFsdGggSW5zdXJhbmNlJyksDQogICAgICAgeT1+Q291bnR5LCB4PX5hZGRlZCwgdHlwZT0nYmFyJywgY29sb3I9fkNvdW50eSwgY29sb3JzPWNvbG9yX25hKQ0KY292ZXJhZ2UgJT4lIGRpc3RpbmN0KE1lYXN1cmUpDQpgYGANCiMgSG91c2luZw0KIyMgSG91c2luZyBBZ2UNCmBgYHtyfQ0KaG91c2luZyAlPiUgZmlsdGVyKFllYXIgPT0gMjAxNykgJT4lDQogIGdncGxvdChhZXMoeD0gQ291bnR5LCB5ID0gWWVhci1OdW1lcmF0b3JfdmFsdWUsIGZpbGwgPSBDb3VudHkpKSArDQogIGdlb21fY29sKCkgKw0KICBjb29yZF9mbGlwKCkNCiMgYXhpcyBpcyBnaXZpbmcgZG91YmxlIHRoZSB0cnVlIHZhbHVlDQpwbG90X2x5KGhvdXNpbmcgJT4lIGZpbHRlcihZZWFyID09IDIwMTQpLCB5PX5Db3VudHksIHg9fmRpZmYsDQogICAgICAgIGNvbG9yPX5Db3VudHksIGNvbG9ycz1jb2xvcl9uYSwgdHlwZT0nYmFyJykNCmBgYA0KIyBTb2NpYWwgV2VsbC1CZWluZw0KIyMgUG92ZXJ0eQ0KYGBge3J9DQpwbG90X2x5KHBvdmVydHkgJT4lIGZpbHRlcihZZWFyPT0yMDE0KSwNCiAgICAgICAgeT1+Q291bnR5LCB4PX5OdW1lcmF0b3JfdmFsdWUvRGVub21pbmF0b3JfdmFsdWUsDQogICAgICAgIGNvbG9yPX5Db3VudHksIGNvbG9ycz1jb2xvcl9uYSwgdHlwZT0nYmFyJykgJT4lDQogICAgICBsYXlvdXQoeGF4aXM9bGlzdChyYW5nZT1saXN0KDAsMC4yKSkpDQpgYGANCiMgVHJhbnNwb3J0YXRpb24NCiMjQ29tbXV0aW5nIE1vZGVzDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgV2F5IHRvbyBtYW55IG1pc3NpbmcgdmFsdWVzIHRvIGNyZWF0ZSBhIHN1YnN0YW50aXZlIHZpc3VhbGl6YXRpb24uDQp0cmFuc3BvcnRhdGlvbiAlPiUgZmlsdGVyKFllYXIgPT0gMjAxNCkgJT4lDQogIGdncGxvdChhZXMoeCA9IENvdW50eSwgeSA9IE51bWVyYXRvcl92YWx1ZSwgZmlsbCA9IE1lYXN1cmUsIHBvc2l0aW9uID0gTWVhc3VyZSkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAnZG9kZ2UnKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQoNCg0KDQo=